/**
 * 1、产品性能优化

 * 2、http2.0和htt1.x的区别
 *    新的底层实现机制，http2.0使用二进制格式解析，1.x是基于文本解析,
 *    header实现压缩，1.xheader携带大量信息，2.0使用encoder减少需要传输hedaer的大小
 *    服务端推送
 *    多路复用
 * 3、输入url发生了什么
 *    url解析，缓存检查(强缓存和协商缓存)，dns解析，tcp三次握手，数据传输，4次挥手，页面渲染
 * 4、get和post的区别
 *    在项目中get一般用于从服务器获取的多提交的少，post一般用于给服务器推送消息，获取的少，都是约定的规范
 *    并不是官方的规范。
 *    浏览器对于url地址的长度是有限制的（ie下最大是2K），所以传递的信息不能太多，post基于请求主体传递信息，理论上没有限制，但是实际上为了保证速度，我们需要手动限制
 *    get请求非常容易产生不可控制的缓存，如果两个请求的地址，参数等信息一样，很有可能第二次请求获取的数据还是第一次请求的结果，可以在请求地址后边加上随机数
 *    get请求相对于post来讲相对不安全，类似于url劫持等低端手段，可以把get传递的信息进行肆意获取和修改
 * 5、JSONP
 *    利用script标签不存在域的限制实现出跨域请求（弊端：只能是get请求，不安全，只要服务器支持，任何人都可以调用）
 * 6、跨域的办法
 *    jsonp、cors、proxy，修改host
 * 7、var a=10，发生了什么
 *    首先创建值，基本值直接存储到栈内存中，引用值单独开辟一块新的内存来存储
 *    声明变量，declare
 *    将变量和值关联到一起
 * 8、数据类型有哪些
 *    基本数据类型：number、string、boolean、undefined、null、bigint、symbol，直接存储到栈中
 *    引用数据类型：function、object，同时存储到堆和栈中，栈中存储了指针，指针指向堆中该实体的起始地址
 * 9、js中数据类型转换
 *    转为布尔值
 *    转为数字 数学运算，基于==比较的时候
 *    转为字符串
 * 10、var a = b = 1;
 *    运算级相同的，从右往左处理 b = 1; var a = b或者 var a = 1；
 *    运算级不同的，优先处理优先级高的，比如a.x = b = 1，优先处理a.x；
 * 11、undefined和undeclared的区别
 *    已经在作用域中声明但是没有赋值的变量是undefined，如果没有声明过的变量就是undeclared，会在控制台输出 xxx is not defined，但是typeof一个不存在的变量会打印undefiend
 * 12、NaN == NaN，结果为false，但是Object.is(NaN,NaN)结果为true，is方法内部做了处理
 * 13、parseInt、parseFloat和Number的区别
 *    parseInt、parseFloat解析一个字符串，并返回一个整数，可以传递第二个参数，表示几进制，值为2-36之前，如果没有或0，默认为10进制
 *    Number()传递一个不是纯数字的字符串，不能解析，直接返回NaN，Number(null)结果为0
 * 14、当前上下文中的某些内容一般是指堆空间，被上下文以外的事物占用了，无法出战释放，一旦释放后期外部事物就无法找到对应的内容。
 *    闭包概念：函数执行会形成自己的私有上下文，在这个上下文中的变量和上下文以外的变量互不干扰，也就是当前上下文中的变量被保护
 *    起来，我们把这种保护机制成为闭包[闭包不是具体代码，而是一种机制，我们常说的是大函数返回小函数，是闭包的具体代码实现]
 *    市面上很多人认为，形成私有上下文很容易被释放，这种保护的机制时间太短了，不是严格意义上的闭包，他们认为只有形成上下文
 *    不被释放，才是闭包，而此时不仅保护了私有变量，而且这些变量存储的值也不会被释放掉，保存起来了。闭包的两个功能是保存和保护。
 *    我们利用闭包这两个特性可以实现很多高阶编程技巧。
 * 15、在浏览器端运行JS代码，非函数中的this一般都是window；研究this都是研究函数中的this。自执行函数中this指向window，回调函数中的this一般也是window
 *    五种this场景: 
 *    事件绑定this指向事件对象，
 *    普通函数执行，看前边得.，自执行函数，this指向window，回调函数this一般也指向window，括号表达中的this很变态
 *    构造函数执行
 *    箭头函数执行
 *    基于call、apply、bind强制改变this
 * 16、let a= 2; 5+a++; 先进行5+a，然后a++
 * 17、浏览器的垃圾回收机制
 *    谷歌：查找引用。当浏览器引擎会在空闲的时候去遍历堆栈内存，当堆内存如果被占用，则不能被释放，如果没有任何的事物占用这个堆，浏览器会自动把这个堆内存释放掉。遍历栈内存时，
 *    当前上下文是否有内容被上下文以外的内容占用，如果占用则不被释放
 *    ie：引用计数。每一个内存中都有一个数字N，记录被占用的次数。每当内存被占用一次，N就加一。反之取消占用，N就会减一，减到0为止。N为0时，就释放掉内存。
 * 18、哪些操作造成内存泄露
 *     事件监听、监听完以后及时清除，
 *     闭包、处理函数定义到外部，解除闭包
 *     计时器或回调函数、定时器中有dom引用，都没删除了，定时器还在，手动清除dom和定时器，移除事件监听。
 *     意外的全局变量、全局变量会挂载到window上，尽可能避免使用全局变量
 *     脱离 DOM 的引用 ，比如dom删除，对dom 的引用还在，我们需要手动删除
 * 19、利用闭包的机制，可以实现很多高阶编程，比如模块化思想，惰性函数，柯里化函数（react高阶组件，节流和防抖，bind），compose组合函数
 *    防抖：触发高频事件后n秒内函数只会执行一次，如果n秒内高频事件再次被出发，则重新计算时间。
 *     实现：每次触发事件
 *    节流：触发高频事件，但是在n秒内只会执行一次，所以节流会稀释函数的执行频率。
 * 20、每一个对象都是一个单独的实例，用来管理自己的私有信息，即使名字相同，也互不影响，其实这就是“JS中的单例设计模式”
 * 21、第一次执行getCss我们已经知晓是否兼容了，第二次及以后再次执行getCss，则不想在处理兼容的校验了，其实这种思想就是“惰性思想”「懒，干一次可以搞定的，绝对不去做第二次」
 * 22、函数柯理化：预先处理的思想「形成一个不被释放的闭包，把一些信息存储起来，以后基于作用域链，访问到事先存储的信息，然后进行相关的处理，所有符合这种模式（或者闭包应用的）都被称为柯理化函数」
 * 23、组合函数：它接受任意多个函数作为参数（这些函数都只接受一个参数），然后compose返回的也是一个函数
 * 24、除函数\对象等大括号外，在其他得大括号中出现let\const\function\则会形成块级私有上下文
 * 25、new函数()和普通函数的区别
 *    相似：一样把函数执行，形成私有上下文，存在私有变量
 *    不同： new执行的时候，会在当前上下文默认创建一个对象（也可以叫实例对象），在初始化this的时候，让this指向这个对象，代码中编写this.xxx=m的操作，都是给实例对象设置私有属性，除了这些操作，
 *        其他操作和实例对象没有直接关系，函数如果没有返回值或者返回值是基本类型值，则默认返回创建的实例对象，如果自己返回的是引用类型值，以自己返回为主。
 * 26、检测这个对象是否含有某个属性，in不管是私有还是公有，如果有就返回true，hasOwnProperty只检测属性是不是这个对象的私有属性
 * 27、Object.getPrototypeOf(obj1)，获取obj1这个实例对象的原型
 * 28、for in遍历对象的时候，无法遍历Symbol的私有属性，但是可以遍历到自己扩展的公共属性，优先遍历数字属性，而且按照从小到大
 * 29、对象成员访问或者遍历对象，首先找自己的私有属性，私有中存在的话就使用私有的，私有中不存在，则默认基于__proto__到所属类的prototype上去找，如果还没有，则基于prototype的__proto__继续查找，
 *    直到Object.prototype为止，我们把这一整套查找机制，称为原型链
 * 30、Object.assign() 浅合并
 * 31、fn(){}和fn:function(){}的区别
 *    写法一obj.fn1函数是没有prototype属性的，不能作为构造函数，写法二和正常函数没有区别
 * 32、原型重定向
 *    优势：把原型上为其实例提供的公共属性和方法，全部写在一起了，提高整体性和模块性。以后向原型上扩展属性或者方法更容易一些。
 *    弊端：重定向后的原型对象中，缺失了constructor属性，解决：手动设置一个constructor属性，如果原始内置的原型对象中具备了一些属性和方法，重定向后，都会丢失。解决：Object.assign()合并
 * 33、箭头函数中没有自己的this，所用到的this都是所处上下文中的this，没有arguments，不能new，没有原型
 * 34、实现数组克隆，var a = arr.slice()，slice返回一个新数组
 * 35、url解析，为什么进行url解析（编码）。网络协议中规定，url中只能是字母和数字还有一些特殊的字符，如果不转义会出现歧义。比如key=value，
 *    url编码规则utf8，为什么要用utf8，可能跟html本身编码格式有关。怎么保证utf8编码，encodeURI和encodeURIComponent，后者范围更广，适合给参数编码，前者适合给url本身编码，当然
 *    项目中我们一般用qs库去处理。
 * 36、先去查host文件是否有记录，如果有把映射的ip返回。没有的话查本地dns解析器有没有，没有的话查计算机配置的dns服务器上有没有，没有的话去根dns服务器找。看.com域名是哪个服务器，baidu.com
 *    服务器能解析，直到找到www.baidu.com
 * 37、dns优化，可以再html页面头部写入dns缓存,link标签，dns-prefetch，每个dns解析在20ms到100ms之间。
 * 38、tcp三次握手，
 *    主机a发送tcp包给服务器，并且随机产生一个确认号，服务器收到后知道a要求建立连接
 *    服务器收到请求后向a发送确认号和tcp包
 *    a收到后检查确认号是否正确，如果正确a再次发送确认号，主机b收到后确认则连接建立成功。
 * 39、为什么两次握手不行
 *    因为第二次握手，服务器还不能确认a已经收到确认请求，B认为建立好了连接，发送数据，但是A一直没收到，服务器一直发包不接收，很容易就挂了。
 * 40、浏览器在加载资源成功时，不仅将资源加载下来，而且根据响应头信息进行缓存下来。浏览器的缓存分为强缓存和协商缓存，在强缓存失效后才到协商缓存。强缓存cache-control优先级最高，
 *    值为no-cache直接进入到协商缓存步骤。max-age会比较当前时间和上次成功时间差，和max-age对比。如果没有cache-control，贼会去expirse的值，看看是否过期。
 *    协商缓存向服务器发送header中if-none-match，服务器会比较etag，如果相同，命中协商缓存，返货304，if-modified-since获取文件最近改动时间。
 *    启发式缓存，请求头没有任何缓存的信息，缓存可以使用启发式方法计算新鲜度寿命。
 *    
 * 41、es6基于class创建的类，只能new执行，无法当作普通函数执行
 * 42、Symbol.toPrimitive
 * 43、promise实现异步，一般是基于promise中resolve的执行或者reject的执行改变promise的状态，出发.then()中回调函数的执行。async和await能够实现异步，await本身就是异步微任务，把await以下的代码放到异步微任务中，
 *    对失败的promise实例没有做异常的处理，则控制台抛出异常信息「不会影响后续代码执行」
 *    promise.catch捕获异常，await需要自己基于try catch做异常捕获
 * 44、所以html页面完全可以设置协商缓存，而其余的资源文件一般是两种都设置！！
 * 45、js继承方式
 *    原型继承（让子类的原型等于父类的实例）
 *    call 继承 （在子类构造函数中，把父类当作普通方法执行，没有父类实例，父类原型上的那些东西也就和他没有关系了）只能继承父类私有的，不能继承共有的
 *    寄生式继承
 * 45、客户端解析服务器代码
 *      自上而下渲染解析代码的过程是同步的，但是有些操作是异步的
 *      1、css资源的加载
 *          遇到style内嵌样式，同步交给gui渲染线程解析
 *          遇到link外链样式，异步开一个新的http请求，不等待资源信息回来，继续向下渲染，等同步操作都处理完后，再把请求回来的文件进行解析渲染
 *          遇到import导入样式，同步开辟新的http请求，在资源文件没有请求回来之前，渲染工作处于等待状态，
 *      2、script请求
 *          默认都是同步的，必须基于http，把资源请求回来以后交给js渲染线程渲染解析完成后，gui渲染线程才能继续向下渲染。script默认也是阻碍
 *          gui渲染的。
 *          async属性，开辟http请求去请求资源，不会阻碍gui向下渲染，当资源请求回来以后，会中断gui渲染，把请求回来的js进行解析
 *          defer属性，开辟http请求，当资源请求回来以后，gui继续渲染，渲染完毕以后再把请求回来的js进行解析
 *      3、遇到img或者video，遇到媒体资源也会发送http请求，不会阻碍gui的渲染，等渲染完以后再去把请求回来的资源进行解析
 * 46、回流：根据生成的渲染树，计算他们在设备窗口中的确切位置和大小，这个计算的阶段就是回流（重排）（布局）。元素的大小位置变化触发回流
 * 47、分层：按照层级定位分层处理，每一个层级都会有详细规划出具体的绘制步骤。
 * 48、重绘：按照每一个层级计算处理的绘制步骤，开始绘制页面。元素样式改变，宽高大小位置不变
 * 49、生成dom树：减少dom的层级嵌套，标签语义化，
 * 50、cssom树：尽可能不要使用@import导入css样式，如果css代码量较少，尽可能使用style内嵌样式，如果使用link。尽可能减少css请求，合并为一个
 *      css选择器链短一些，因为css选择器渲染是从右向左渲染，把link导入放到head标签中
 * 51、script标签尽可能放在标签尾部，防止阻塞gui渲染。async是不管js的依赖关系的，哪一个先获取到，就把哪个先执行。defer和link一样，等待
 *      所有 script defer都请求回来以后，按照导入顺序/依赖关系一次渲染执行的
 * 52、对于img
 *      懒加载：第一次加载页面的时候，不要加载请求图片，哪怕他是异步，但是也占据了http的并发量
 *      图片base64
 * 53、减少回流和重绘：第一次加载页面必然回流和重绘，回流必然重绘
 * 54、box.style.width = '100px';box.style.height='100px';box.style.position='absolute';box.style.top='100px'，当代浏览器：触发1次，
 *      放到渲染队列中一次性进行渲染。
 *      在现代浏览器中，当前上下文操作中，遇到一行修改样式的代码，并没有立即通知浏览器渲染，而是把其放置在渲染队列中，接下来看是否还有修改
 *      样式的代码，如果有，继续放置在渲染队列中，一直到没有修改样式的代码或者遇到一行获取样式的操作，这样都会刷新浏览器的渲染队列机制。
 *      获取样式操作：box.style.xxx，window.getComputedStyle(box).xxx，box.clientWidth|Height|Top|Left，box.offsetWidth|Height|Top|Left
 *      box.scrollWidth|Height|Top|Left
 * 55、减少dom回流：
 *      样式的分离独写：把修改样式和获取样式代码分离开
 *      样式集中改变，box.style.cssText="
 *      提前获取样式信息
 *      虚拟dom
 *      把动画等频发样式改变的操作，运用到position:fixed/absolute上，脱离文档流，单独的一层
 *      修改元素的transform/opacity/不会引发dom的回流
 * 56、http方法：get/post/options/head/
 * 57、线程和进程
 * 58、for  in  key的值
 *     for of 属性值
 * 59、class继承 子类super()相当于A.prototype.constructor.call(this)
 * 60、es7新增字符串方法padStart，补全字符串前边的值
 *      'ab'.padStart(4) => '  ab'； 'ab'.padStart(4,'12') => '12ab'
 * 61、箭头函数中的this指的是他定义时所在的上下文，对象的某个属性的值为箭头函数，这个箭头函数中this指的是window
 * 62、Object.seal(obj)，Object.seal方法防止给对象新增属性或者存在的属性被删除，可以对属性进行修改
 * 63、Object.freeze(obj)，Object.freeze方法为浅冻结，不能对属性进行添加修改和删除，如果属性的值为Object，则对Object不起作用，所以是浅冻结
 * 64、Number.isNaN()方法是es6新增的方法，用来检测值是否为NaN，isNaN()是es5中的方法，检测参数是不是一个数值
 * 65、function a(...args){} es6引入rest（剩余的）参数，  args是个数组
 * 66、es6引入class类，在constructor函数中，this.name等属性为构造函数私有属性，this.getName也为私有方法，在构造函数以外设置属性，也会认为私有属性，
 *     在constructor以外设置方法，如果按照正常的声明函数形式或者箭头函数，则为私有方法，如果是简写getAge(){}，则会加到原型上。
 */